/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "fatfs.h"
#include "w25q64.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId defaultTaskHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 2048);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  UINT fnum;                          /* 文件成功读写数量 */
  int8_t ReadBuffer[1024] = {0};        /* 读缓冲区 */
  int8_t WriteBuffer[]= "Hello World!\n";
  W25QXX_Erase_Sector(0);
  printf("****** 这是一个SPI FLASH 文件系统实验 ******\r\n");

  // 在外部SPI Flash挂载文件系统，文件系统挂载时会对SPI设备初始化
  retUSER = f_mount(&USERFatFS, USERPath, 1);
  /*----------------------- 格式化测试 -----------------*/  
  /* 如果没有文件系统就格式化创建创建文件系统 */
  if(retUSER == FR_NO_FILESYSTEM)
  {
    printf("》FLASH还没有文件系统，即将进行格式化...\r\n");
    /* 格式化 */
    retUSER = f_mkfs(USERPath, 0, 0);	    
		
    if(retUSER == FR_OK)
    {
      printf("》FLASH已成功格式化文件系统。\r\n");
      /* 格式化后，先取消挂载 */
      retUSER = f_mount(NULL, USERPath, 1);

      /* 重新挂载	*/			
      retUSER = f_mount(&USERFatFS, USERPath, 1);
      printf("》文件系统重新挂载 %s\r\n", retUSER == FR_OK ? "成功" : "失败");
    }
    else
    {
      printf("《《格式化失败。》》\r\n");
      while(1) osDelay(1);
    }
  }
  else if(retUSER != FR_OK)
  {
    printf("！！外部Flash挂载文件系统失败。(%d)\r\n", retUSER);
    printf("！！可能原因：SPI Flash初始化不成功。\r\n");
    while(1) osDelay(1);
  }
  else
  {
    printf("》文件系统挂载成功，可以进行读写测试\r\n");
  }
  
  /*----------------------- 文件系统测试：写测试 -------------------*/
  printf("\r\n****** 即将进行文件写入测试... ******\r\n");	
  retUSER = f_open(&USERFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
  if(retUSER == FR_OK)
  {
    printf("》打开/创建FatFs读写文件test.txt文件成功，向文件写入数据。\r\n");
    /* 将指定存储区内容写入到文件内 */
    retUSER = f_write(&USERFile, WriteBuffer, sizeof(WriteBuffer), &fnum);
    if(retUSER == FR_OK)
    {
      printf("》文件写入成功，写入字节数据：%d\n", fnum);
      printf("》向文件写入的数据为：\r\n%s\r\n", WriteBuffer);
    }
    else
    {
      printf("！！文件写入失败：(%d)\n", retUSER);
    }    
    /* 不再读写，关闭文件 */
    f_close(&USERFile);
  }
  else
  {	
    printf("！！打开/创建文件失败。\r\n");
  }
	
/*------------------- 文件系统测试：读测试 --------------------------*/
	printf("****** 即将进行文件读取测试... ******\r\n");
	retUSER = f_open(&USERFile, "test.txt",FA_OPEN_EXISTING | FA_READ); 	 
	if(retUSER == FR_OK)
	{
		printf("》打开文件成功。\r\n");
		retUSER = f_read(&USERFile, ReadBuffer, sizeof(ReadBuffer), &fnum); 
    if(retUSER==FR_OK)
    {
      printf("》文件读取成功,读到字节数据：%d\r\n",fnum);
      printf("》读取得的文件数据为：\r\n%s \r\n", ReadBuffer);	
    }
    else
    {
      printf("！！文件读取失败：(%d)\n",retUSER);
    }		
	}
	else
	{
		printf("！！打开文件失败。\r\n");
	}
	/* 不再读写，关闭文件 */
	f_close(&USERFile);	

  /*----------------------- 文件系统测试：读取目录测试 -------------------*/
  printf("\r\n****** 即将进行文件系统目录读取测试... ******\r\n");
  DIR dir;
  FILINFO fno;
  retUSER = f_opendir(&dir, USERPath);
  if (retUSER == FR_OK) {
    printf("》目录打开成功，目录内容如下：\r\n");
    for (;;) {
      retUSER = f_readdir(&dir, &fno);
      if (retUSER != FR_OK || fno.fname[0] == 0) break;
      if (fno.fattrib & AM_DIR) {
        printf("  [DIR]  %s\r\n", fno.fname);
      } else {
        printf("  [FILE] %s (Size: %ld bytes)\r\n", fno.fname, fno.fsize);
      }
    }
    f_closedir(&dir);
  } else {
    printf("！！目录打开失败。(%d)\r\n", retUSER);
  }
  
	/* 不再使用文件系统，取消挂载文件系统 */
	f_mount(NULL,"1:",1);

  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

